
let templateEditor = ace.edit('templateEditor');
let template2Editor = ace.edit('template2Editor');
let nacosServersEditor = ace.edit('nacosServersEditor');
let keymap = ace.edit('keymap');
let configEditor = ace.edit('configEditor');
let resultEditor = ace.edit('resultEditor');

const app = new Vue({
    el: '#app',
    data: {
        basePath: '',
        groupId: '',
        groups: [],
        configs: [],
        addGroupVisible: false,
        groupForm: {groupName: '', fileType: ''},
        templateForm: {name: '', fileType: '', content: '', comment: '', nacosGroup: '', nacosNamespace: ''},
        page1: true,
        page2: false,
        page3: false,
        page4: false,
        isTemplateEdit: false,
        templates: [],
        templatesBack: [],
        templateIds: [],
        tempId: '',
        template: {},
        template2: '',
        addTemplateVisible: false,
        results: [],
        resultsBack: [],
        selectTemplateVisible: false,
        selectTemplateChekAll: false,
        selectTemplateChecked: [],
        isTemplateIndeterminate: false,
        selectTemplate2Visible: false,
        selectTemplate2ChekAll: false,
        selectTemplate2Checked: [],
        isTemplate2Indeterminate: false,
        search: '',
        searchTime: [],
        selectResultVisible: false,
        selectResultChekAll: false,
        selectResultChecked: [],
        isResultIndeterminate: false,
        resultIds: [],
        codeClass: {
            'language-yaml': true
        },
        result: {},
        pushNacosVisible: false,
        oldText: '',
        nacosServer: '',
        nacosServers: [],
        namespaces: [],
        templateSearch: '',
        template2Search: '',
        downloadSearch: '',
        nacosServersStr: ''
    },
    mounted: function () {
        this.getGroups(function () {
            if (app.groups !== undefined && app.groups.length > 0) {
                app.groupId = app.groups[0].id;
                app.getConfigs()
            }
        });

        this.getTemplates(function () {
            app.tempId = app.templates[0].id;
            app.template = app.templates[0];
            templateEditor = app.doAce(templateEditor, 'templateEditor', app.template.fileType, app.template.content)
        });

        this.getNacosServers(function () {
            app.nacosServer = app.nacosServers[0];
        });
    },
    methods: {
        handleSelect(key) {
            this.page1 = key === '1';
            this.page2 = key === '2';
            this.page3 = key === '3';
            this.page4 = key === '4';

            if (this.page1) {
                this.getGroups();
            }
            if (this.page2) {
                this.getTemplates();
            }
            if (this.page3) {
                this.getResults();
                if(this.nacosServers && this.nacosServers.length > 0) {
                    this.getNacosNamespaces();
                }
            }
            if (this.page4) {
                nacosServersEditor = this.doAce(nacosServersEditor, 'nacosServersEditor', 'json', this.nacosServersStr);
                keymap = this.doAce(keymap, 'keymap', 'markdown', keymap.getValue(), 40, true);
                keymap.renderer.setShowGutter(false);
            }
        },
        getGroups(callback) {
            try {
                axios.get(this.basePath + 'groups').then(
                    resp => {
                        this.groups = resp.data.data
                        if(callback) {
                            callback()
                        }
                    }
                )
            } catch (errors) {
                this.errorNotify('查询参数组失败')
                console.error(errors)
            }
        },
        getConfigs() {
            try {
                axios.get(this.basePath + 'configs/group/' + this.groupId).then(
                    resp => {
                        if (resp.data.code === 0) {
                            app.configs = resp.data.data
                            let txt = '';
                            if (app.configs !== undefined) {
                                for (let i = 0; i < app.configs.length; i++) {
                                    txt += app.configs[i].ckey + '=' + app.configs[i].cvalue;
                                    if (i !== app.configs.length - 1) {
                                        txt += "\n";
                                    }
                                }
                            }
                            configEditor = this.doAce(configEditor, 'configEditor', 'properties', txt);

                        } else {
                            this.errorNotify(resp.data.message)
                            console.error(resp.data)
                        }
                    }
                )
            } catch (errors) {
                this.errorNotify('查询参数列表失败')
                console.error(errors)
            }

        },
        saveConfigs() {
            let configsText = configEditor.getValue();

            if (configsText.replace(/(^\s*)|(\s*$)/g, "").length === 0) {
                this.infoNotify("数据不能为空")
                return;
            }

            let configs = [];
            let strings = configsText.split("\n");
            for (let i = 0; i < strings.length; i++) {
                let str = strings[i];
                if (str.replace(/(^\s*)|(\s*$)/g, "").length === 0) {
                    continue;
                }

                if (!str.includes('=')) {
                    this.errorNotify("第" + (i + 1) + "行数据[" + str + "]的格式不正确</br>正确格式为：key=value")
                    return;
                }
                let index = str.indexOf('=');
                configs.push({cKey: str.substr(0, index).trim(), cValue: str.substr(index+1).trim(), sort: configs.length + 1})
            }

            this.post(this.basePath + 'configs/group/' + this.groupId, configs, "", function () {
                app.successNotify("保存成功！")
                app.getConfigs()
            })
        },
        addGroup() {
            axios.post(app.basePath + 'groups/' + this.groupForm.groupName).then(
                resp => {
                    if (resp.data.code === 0) {
                        this.successNotify("新增组成功");
                        this.getGroups();
                        this.addGroupVisible = false
                    } else {
                        this.errorNotify(resp.data.message)
                        console.error(resp.data)
                    }
                }
            )
        },
        errorNotify(message) {
            this.$notify.error({
                title: '错误',
                dangerouslyUseHTMLString: true,
                message: message
            });
        },
        successNotify(message) {
            this.$notify.success({
                title: '成功',
                message: message
            });
        },
        infoNotify(message, duration) {
            if (!duration) {
                duration = 1000;
            }
            this.$notify({
                title: '提示',
                message: message,
                duration: duration
            });
        },
        getCharCount(str, char) {
            const regex = new RegExp(char, 'g'); // 使用g表示整个字符串都要匹配
            const result = str.match(regex);          //match方法可在字符串内检索指定的值，或找到一个或多个正则表达式的匹配。
            return !result ? 0 : result.length;
        },
        getTemplates(callback) {
            try {
                axios.get(this.basePath + 'templates').then(
                    resp => {
                        if (resp.data.code === 0) {
                            this.templates = resp.data.data;
                            this.templatesBack = this.templates;
                            if (this.templates !== undefined && this.templates.length > 0) {
                                this.templateIds = []
                                for (let i = 0; i < this.templates.length; i++) {
                                    this.templateIds.push(this.templates[i].id)
                                }
                                if(callback) {
                                    callback()
                                }
                            }
                        } else {
                            this.errorNotify(resp.data.message)
                            console.error(resp.data)
                        }
                    }
                )
            } catch (errors) {
                this.errorNotify('查询模板列表失败')
                console.error(errors)
            }
        },
        getTemplate() {
            for (let i = 0; i < this.templates.length; i++) {
                if (this.tempId === this.templates[i].id) {
                    this.template = this.templates[i];
                    templateEditor = this.doAce(templateEditor, 'templateEditor', this.template.fileType, this.template.content)
                    return;
                }
            }
        },
        searchTemplateAndCheck() {
            this.templates = this.templatesBack;
            let results = [];
            for (let i = 0; i < this.templates.length; i++) {
                let template = this.templates[i];
                if (template.name.includes(this.templateSearch) || template.version.includes(this.templateSearch)) {
                    results.push(template);
                }
            }
            this.templates = results;
            this.templateIds = []
            for (let i = 0; i < this.templates.length; i++) {
                this.templateIds.push(this.templates[i].id)
            }
        },
        searchTemplate2AndCheck() {
            let results = [];
            this.templates = this.templatesBack;
            for (let i = 0; i < this.templates.length; i++) {
                let template = this.templates[i];
                if (template.name.includes(this.template2Search) || template.version.includes(this.template2Search)) {
                    results.push(template);
                }
            }
            this.templateIds = []
            this.templates = results;
            for (let i = 0; i < this.templates.length; i++) {
                this.templateIds.push(this.templates[i].id)
            }
        },
        updateTemplate() {
            this.template.content = templateEditor.getValue();
            this.post(this.basePath + 'template', this.template, '更新模版失败', function () {
                app.successNotify("更新成功");
                app.getTemplates();
            });
        },
        addTemplate() {
            this.templateForm.content = template2Editor.getValue();
            this.templateForm.id = '';
            this.post(this.basePath + 'template', this.templateForm, '新增模版失败', function () {
                app.successNotify("新增成功");
                app.getTemplates();
                app.addTemplateVisible = false;
            });
        },
        openAddTemplate() {
            this.addTemplateVisible = true;
            template2Editor.setValue('');
        },
        copyTemplate() {
            this.templateForm = this.template;
            template2Editor.setValue(templateEditor.getValue());
            this.addTemplateVisible = true;
        },
        getResults() {
            let timeSearch = '';
            if (this.searchTime && this.searchTime.length > 0) {
                timeSearch = '&startTime=' + this.searchTime[0] + '&endTime=' + this.searchTime[1];
            }
            this.get(this.basePath + 'results?search=' + this.search + timeSearch, '查询生成结果失败', function (results) {
                app.resultIds = [];
                app.results = results;
                app.resultsBack = results;
                if (!app.results) {
                    return;
                }
                for (let i = 0; i < app.results.length; i++) {
                    app.resultIds.push(app.results[i].id)
                }
            })
        },
        clearResult() {
            this.get('results/clear', '清除失败', function () {
                app.successNotify("清除成功");
                app.getResults();
            })
        },
        searchDownloadAndCheck() {
            this.results = this.resultsBack;
            let results = [];
            for (let i = 0; i < this.results.length; i++) {
                let result = this.results[i];
                if (result.fileName.includes(this.downloadSearch) || result.version.includes(this.downloadSearch)) {
                    results.push(result);
                }
            }
            this.resultIds = []
            this.results = results;
            for (let i = 0; i < app.results.length; i++) {
                app.resultIds.push(app.results[i].id)
            }
        },
        handleCheckAllChange(val) {
            this.selectTemplateChecked = val ? this.templateIds : [];
            this.isTemplateIndeterminate = false;
        },
        handleCheckAllChange2(val) {
            this.selectTemplate2Checked = val ? this.templateIds : [];
            this.isTemplate2Indeterminate = false;
        },
        handleCheckAllResult(val) {
            this.selectResultChecked = val ? this.resultIds : [];
            this.isResultIndeterminate = false;
        },
        handleCheckedTemplateChange(value) {
            this.selectTemplateChekAll = this.selectTemplateChecked.length === this.templates.length;
        },
        handleCheckedTemplate2Change(value) {
            this.selectTemplate2ChekAll = this.selectTemplate2Checked.length === this.templates.length;
        },
        handleCheckedResultChange(value) {
            this.selectResultChekAll = this.selectResultChecked.length === this.results.length;
        },
        genConfigTemplate() {
            this.post(this.basePath + "gen/" + this.groupId, this.selectTemplateChecked, "", function (data) {
                app.successNotify("生成成功！");
                app.getResults();
                app.selectTemplateVisible = false;
                app.getTemplates();
            })
        },
        handleCurrentChange(val) {
            if (val !== null) {
                let fileType = val.fileType === undefined ? 'txt' : val.fileType;
                const reg = /[A-Za-z]+/
                if (!reg.test(fileType)) {
                    fileType = 'text';
                }

                this.result = val;
                resultEditor = this.doAce(resultEditor, 'resultEditor', fileType, val.fileContent);
                resultEditor.setReadOnly(true);
            }
        },
        download() {
            if (this.selectResultChecked.length === 0) {
                this.$message.error('未选择下载内容');
                return
            }

            fetch(this.basePath + "download",
                {
                    method: 'POST',
                    headers: {
                        'Accept': 'application/json',
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(this.selectResultChecked)
                }
            ).then(res => res.json()).then(res => {
                console.log(res)
                if (res.code === 0) {
                    app.selectResultVisible = false;
                    var a = document.createElement('a');
                    a.href = app.basePath + 'download/' + res.data;
                    a.download = res.data;
                    a.click();
                } else {
                    app.errorNotify(res.message);
                }
            })
        },
        get(path, errorMessage, callback) {
            try {
                axios.get(path).then(
                    resp => {
                        if(resp.status !== 200) {
                            app.errorNotify(resp.statusText);
                            console.error(resp);
                            return;
                        }

                        if (resp.data.code === 0) {
                            callback(resp.data.data);
                        } else {
                            app.errorNotify(resp.data.message);
                            console.error(resp.data);
                        }
                    }
                )
            } catch (errors) {
                this.errorNotify(errorMessage);
                console.error(errors);
            }
        },
        post(path, body, errorMessage, callback) {
            try {
                axios.post(path, body).then(
                    resp => {
                        if(resp.status !== 200) {
                            app.errorNotify(resp.statusText);
                            console.error(resp);
                            return;
                        }

                        let result = resp.data
                        if (result.code !== 0) {
                            this.errorNotify(result.message)
                            console.error(result)
                        } else {
                            callback(resp.data.data)
                        }
                    }
                )
            } catch (errors) {
                this.errorNotify(errorMessage)
                console.error(errors)
            }
        },
        defaultValue(obj, def) {
            return obj === undefined ? def : obj;
        },
        compareContent() {
            axios.get(this.nacosServer
                + '/nacos/v1/cs/configs?dataId='
                + this.result.fileName + '&group='
                + this.result.nacosGroup + '&tenant='
                + this.result.nacosNamespace).then(
                resp => {
                    if (resp.status !== 200) {
                        app.errorNotify('获取nacos上的配置失败： ' + resp.statusText)
                    } else {
                        app.oldText = resp.data;
                        app.showCompare(resp.data);
                    }
                })
                .catch(e => {
                    app.errorNotify('查询nacos配置失败: ' + e)
                })
        },
        showCompare(oldText) {
            const targetElement = document.getElementById('compare');
            //outputFormat line-by-line side-by-side
            const configuration = {outputFormat: 'line-by-line', drawFileList: false, matching: 'lines', renderNothingWhenEmpty: false, diffStyle: 'word'};
            let diff = Diff.createPatch(app.result.fileName, oldText, this.result.fileContent.replace(/(?<!\r)\n/g, '\r\n'));

            const diff2htmlUi = new Diff2HtmlUI(targetElement, diff, configuration);
            diff2htmlUi.draw();
        },
        pushNacos() {
            const formData = new FormData();
            const formData2 = {};
            Object.keys(this.result).forEach((key) => {
                let rKey = key;
                if (key === 'fileName') {
                    rKey = 'dataId';
                    formData2.dataId = this.result[key];
                }
                if (key === 'nacosGroup') {
                    rKey = 'group';
                    formData2.group = this.result[key];
                }
                if (key === 'fileContent') {
                    rKey = 'content';
                    formData2.content = this.result[key];
                }
                if (key === 'fileType') {
                    rKey = 'type';
                    formData2.type = this.result[key];
                }
                if (key === 'nacosNamespace') {
                    rKey = 'tenant';
                    formData2.tenant = this.result[key];
                }
                formData.append(rKey, this.result[key]);
            });
            formData.set('username', 'config-gen');

            axios.post(this.nacosServer + '/nacos/v1/cs/configs', formData).then(
                resp => {
                    if (resp.status !== 200) {
                        app.errorNotify('保存配置失败: ' + resp.statusText)
                    } else {
                        if (resp.data) {
                            app.successNotify("保存配置成功！")
                            app.pushNacosVisible = false;
                        }
                    }
                })
                .catch((resp) => {
                    app.errorNotify(resp.response.data);
                });

            formData2.oldContent = this.oldText;
            formData2.version = this.result['version'];
            axios.post(this.basePath + 'pushLog', formData2).then(() => {}).catch(() => {});
        },
        getNacosNamespaces() {
            if (!this.nacosServer) {
                app.errorNotify("请选择nacos服务！")
                return;
            }

            axios.get(this.nacosServer + '/nacos/v1/console/namespaces').then(
                resp => {
                    if (resp.status !== 200) {
                        app.errorNotify('获取nacos命名空间失败: ' + resp.statusText)
                    } else {
                        if (resp.data.code === 200) {
                            app.namespaces = resp.data.data;
                        } else {
                            app.errorNotify(resp.data.message);
                        }
                    }
                })
                .catch(e => {
                    app.errorNotify('获取nacos命名空间失败: ' + e)
                })
        },
        getNacosServers(callback) {
            this.get(this.basePath + 'nacos-servers', '获取nacos地址失败！', function (data) {
                app.nacosServers = data;
                app.nacosServersStr = JSON.stringify(data);
                if (callback) {
                    callback()
                }
            });
        },
        saveNacosServers() {
            this.nacosServersStr = nacosServersEditor.getValue();
            if(!this.nacosServersStr || this.nacosServersStr.length === 0) {
                this.errorNotify("nacos地址内容不能为空");
                return;
            }

            let body;
            try {
                body = JSON.parse(this.nacosServersStr);
            } catch (e) {
                this.errorNotify("nacos地址格式不正确，正确格式为字符串数组");
                return;
            }

            this.post(this.basePath + '/nacos-servers', body, '保存nacos地址失败', function () {
                app.successNotify("保存成功");
                app.getNacosServers(function () {
                    app.nacosServer = app.nacosServers[0];
                });
            });
        },
        parseTemplateConfig() {
            if(!this.selectTemplate2Checked && this.selectTemplate2Checked.length === 0) {
                this.errorNotify("未选择模板");
                return;
            }
            if(!this.groupId) {
                this.errorNotify("未选择配置");
                return;
            }
            this.post(this.basePath + "configs/parse/" + this.groupId, this.selectTemplate2Checked, "解析模板参数失败", function (data) {
                app.successNotify("解析模板参数成功");
                app.selectTemplate2Checked = [];
                app.selectTemplate2Visible = false;
                app.template2Search = '';
            });
        },
        doAce(editor, id, type, value, maxLines, readOnly) {
            if (!type || type.length === 0) {
                type = 'text';
            }
            if (!maxLines) {
                maxLines = 40;
            }
            if (!readOnly) {
                readOnly = false;
            }

            editor.destroy();
            editor = ace.edit(id, {
                theme: "ace/theme/xcode",
                mode: "ace/mode/" + type,
                minLines: 10,
                maxLines: maxLines,
                wrap: true,
                readOnly: readOnly,
                autoScrollEditorIntoView: true
            });

            editor.commands.addCommand({
                name: 'showInvisibles',
                bindKey: {win: 'Ctrl-S',  mac: 'Command-S'},
                exec: function(editor) {
                    let showInvisibles = localStorage.getItem("showInvisibles") === 'true';
                    localStorage.setItem("showInvisibles", !showInvisibles);
                    editor.setShowInvisibles(!showInvisibles);
                },
                readOnly: true
            });

            editor.session.setMode("ace/mode/" + type);
            editor.renderer.setScrollMargin(10, 10, 10, 10);
            editor.setValue(value, 1);
            editor.setShowInvisibles(localStorage.getItem("showInvisibles") === 'true');
            return editor;
        },
        changeAceMode(id, type) {
            if (id === 'templateEditor') {
                let value = templateEditor.getValue();
                templateEditor = this.doAce(templateEditor, id, type, value);
            }
            if (id === 'template2Editor') {
                let value = template2Editor.getValue();
                template2Editor = this.doAce(template2Editor, id, type, value, 20);
                this.template2Editor = template2Editor;
            }

        }
    }
})
